﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
using System.IO;
using System.Globalization;
using debugger;
using SDcard;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Net.Sockets;
using System.Net;
using System.Diagnostics;

using System.Runtime.InteropServices;



namespace debugger
{

    public sealed partial class Form1 : Base
    {
        public const byte SET_DEBUG_RW_CMD = 0x15;//{debug_mem_dummy,debug_rw_cmd} <= data[3:0];

        public const byte MEM_TRANS_READ = 0x34;
        public const byte MEM_TRANS_WRITE = 0x35;
        //public const byte REG_READ = 0x37;
        public const byte TRANS_READ = 0x38;
        public const byte TRANS_WRITE = 0x39;






        public static uint CACHE_CTL = 0x42000000;

        public const byte HALT_DEBUG = 0x10;
        public const byte SET_CPU_CLK = 0x11;
        public const byte DEBUG_RESET_N = 0x12;
        public const byte DEBUG_NOCACHE = 0x13;

        public const byte DEBUG_STEP = 0x14;
        public const byte SET_VGA_CONTROL = 0x15;

        public const byte SET_DEBUG_ADDRESS = 0x16;
        public const byte SET_DEBUG_WRITEDATA = 0x17;
        public const byte SET_DEBUG_VGA_BASE_ADDR = 0x18;
        public const byte SET_DEBUG_FLG = 0x19;
        public const byte SET_DEBUG_HID = 0x1A;
        public const byte SET_DEBUG_HID_REQ = 0x1B;
        public const byte SET_DEBUG_LENGTH = 0x1C;
        public const byte SET_DEBUG_ECHO = 0x1F;

        //public const byte GET_ECHO = 0x1C;
        public const byte GET_CONST_ECHO = 0x20;
        public const byte GET_CONST_VER = 0x24;

        public const byte GET_DEBUG8 = 0x20;
        public const byte GET_DEBUG32 = 0x21;
        public const byte GET_ACCESS_TIME = 0x22;
        public const byte GET_AVM_M0_ADDRESS = 0x23;
        //public const byte GET_PRIVATE_OFFSET_REAR = 0x24;

        public const byte GET_PC_RECORD_DATA = 0x25;
        public const byte GET_PC_RECORD_DATA_EXT = 0x21;
        public const byte GET_PC_RECORD_INDEX = 0x26;
        public const byte GET_MISC = 0x27;
        //public const byte GET_IRQ_ADDR = 0x28;
        public const byte GET_IRQ_ID = 0x28;
        public const byte GET_CPU_ADDRESS = 0x29;
        public const byte GET_PC = 0x2A;
        //public const byte GET_PRIVATE_OFFSET = 0x2B;
        //public const byte GET_PC_RESULT = 0x2C;

        public const byte GET_MEM_SIZE = 0x2B;
        public const byte GET_VGA_BASE_ADDR = 0x2C;

        public const byte GET_DEBUG_STASH_DATA = 0x2E;
        public const byte GET_DEBUG_STASH_INDEX = 0x2F;

        public const byte MEM_READ = 0x30;
        public const byte MEM_WRITE = 0x31;
        public const byte INS_READ = 0x32;
        //public const byte REG_READ = 0x33;
        public const byte MEM_READ_TRANS = 0x34;
        public const byte MEM_WRITE_TRANS = 0x35;
        public const byte INS_READ_TRANS = 0x36;
        public const byte VGA_TRANS = 0x37;

        //public const byte MEM_TRANS_READ = 0x34;
        //public const byte MEM_TRANS_WRITE = 0x35;
        //public const byte TRANS_READ = 0x38;
        //public const byte TRANS_WRITE = 0x39;


        //public const byte DEBUG_TX_TO_PC = 0x40;
        //public const byte DEBUG_TX_STATUS_TO_PC = 0x41;
        //public const byte DEBUG_RX_FROM_PC = 0x42;




        public const byte SPIROM_DEBUG_CS0 = 0x70;
        public const byte SPIROM_DEBUG_CS1 = 0x71;
        public const byte SPIROM_REC = 0x72;
        public const byte SPIROM_SND = 0x73;
        public const byte SPIROM_SND4 = 0x74;
        public const byte SPIROM_TRANS_WRITE = 0x76;


        public Form1()
        {
            InitializeComponent();

            this.FormClosed += new FormClosedEventHandler(Form1_FormClosed);

            this.trackBar1.MouseUp += trackBar1_MouseUp;
            this.trackBar1.MouseDown += trackBar1_MouseDown;

        }

        void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
        }
        string portName;

        System.Threading.Timer t;

        public void afterConnect()
        {
            loadSym();
            try
            {

                var echo = sendCmdRet(GET_CONST_ECHO, 0x12345678);
                if (echo == 0x12345678)
                {
                    var ver = sendCmdRet(GET_CONST_VER);
                    this.Text = "connected echo ok，" + Util.getHex8(ver);
                    Console.WriteLine("connected echo ok，" + Util.getHex8(ver));

                    if (BaseType == "ft232h")
                    {
                        sendCmdNoRes(0x03);
                        sendCmdNoRes(0x02);
                        sendCmdNoRes(DEBUG_RESET_N, 1);
                    }

                    if (BaseType == "cy7c68031a")
                    {
                        sendCmdNoRes(0x03);
                        sendCmdNoRes(0x02);
                    }
                    //t = new System.Threading.Timer(new System.Threading.TimerCallback(this.timer), null, 0, 200);
                    //for (int i = 0; i < 1000; i++)
                    //{
                    //    var ret = sendCmdRet(0x01);
                    //    Console.WriteLine(i + "," + ret + (i != ret ? "*" : ""));
                    //    sendCmdRet(0x02);
                    //}
                }
                else
                {
                    this.Text = "echo error：" + Util.getHex8(echo);
                    Console.WriteLine("echo error：" + Util.getHex8(echo));
                }




                ///////////////////////////////////////////////////////////////
            }
            catch (Exception ex)
            {
                this.Text = "echo ex";
            }

            this.comboBox2.SelectedIndex = 0;
            this.comboBox1.SelectedIndex = 0;

            uint memSize = sendCmdRet(GET_MEM_SIZE);
            //uint pos = memSize / 1024;
            this.textBox7.Text = "0";// "" + (pos - 2 * 1024);

            this.trackBar1.Minimum = -(int)memSize / 2048;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                bool ret = connect(this.afterConnect);
                if (!ret)
                {
                    foreach (var item in this.Controls)
                    {
                        (item as Control).Enabled = false;
                    }
                    this.textBox3.Enabled = true;
                    this.textBox4.Enabled = true;
                    this.button7.Enabled = true;
                }
            }
            catch (Exception ex)
            {
            }
        }



        List<CodeSym> syms;


        private void button4_Click(object sender, EventArgs e)
        {


            try
            {
                getstatus();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }


        public uint getAccessTime()
        {
            if (!isBasic)
            {
                return sendCmdRet(GET_ACCESS_TIME);
            }
            else
            {
                return 0;
            }
        }

        uint waitRequest;

        public void getstatus()
        {
            uint temp;

            int baseaddr = 0;

            //temp = sendCmdRet(GET_CONST_ECHO);
            //if (temp != 0x12345678)
            //{
            //    throw new Exception("checkerror");
            //}

            //temp = sendCmdRet(GET_ECHO, 123);
            //if (temp != 123)
            //{
            //    throw new Exception("checkerror");
            //}

            //sendCmd(SET_TRANSFER_BASE_ADDR, 0);

            StringBuilder sb = new StringBuilder();

            int pc;

            try
            {
                pc = Convert.ToInt32(textBox6.Text, 16);
            }
            catch
            {
                sb.Append("pc:");
                pc = (int)sendCmdRet(GET_PC);
                sb.Append(Util.getHex8(pc));
            }


            uint vgaBase = sendCmdRet(GET_VGA_BASE_ADDR);
            this.textBox7.Text = "" + vgaBase * 2;// "" + (pos - 2 * 1024);


            //sb.Append("  private_offset:");
            //temp = sendCmdRet(GET_PRIVATE_OFFSET);
            //sb.Append(Util.getHex8(temp));

            //sb.Append("  private_offset_rear:");
            //temp = sendCmdRet(GET_PRIVATE_OFFSET_REAR);
            //sb.Append(Util.getHex8(temp));

            sb.Append("  avm_m0_address:");
            temp = sendCmdRet(GET_AVM_M0_ADDRESS);
            sb.Append(Util.getHex8(temp));

            //sb.Append("  pcResult:");
            //temp = sendCmdRet(GET_PC_RESULT);
            //sb.Append(Util.getHex8(temp));

            //sb.Append("  last RtypeCmd:");
            //portWrite((byte)(0x18), (byte)0x00); temp = readFromPort(1); sb.Append(Util.getHex2(temp[0]));

            //4        3         2                  1          0
            //halt_cpu,halt_uart,avm_m0_waitrequest,irq_enable,irq_req
            temp = sendCmdRet(GET_MISC);

            uint halt_cpu = (temp >> 4) & 1;
            sb.Append("  halt_cpu:");
            sb.Append(halt_cpu);

            uint halt_uart = (temp >> 3) & 1;
            sb.Append("  halt_uart:");
            sb.Append(halt_uart);

            sb.Append("  waitRequest:");
            waitRequest = (temp >> 2) & 1;
            sb.Append(waitRequest);

            sb.Append("  waitRequestIns:");
            sb.Append((temp >> 5) & 1);

            sb.Append("  irq_enable:");
            sb.Append((temp >> 1) & 1);

            sb.Append("  irq_req:");
            sb.Append((temp >> 0) & 1);

            sb.Append("  irq_id:");
            temp = sendCmdRet(GET_IRQ_ID);
            sb.Append(temp);

            sb.Append("  cpu_address:");
            temp = sendCmdRet(GET_CPU_ADDRESS);
            sb.Append(Util.getHex8(temp));

            //sb.Append("  curr_data:");
            //temp = sendCmdRet(GET_CURR_DATA);
            //sb.Append(Util.getHex8(temp));

            //if (!isBasic)
            //{
            //    sb.Append("  debugin:");
            //    temp = sendCmdRet(GET_DEBUG8);
            //    sb.Append(Util.getBin8(temp));
            //    sb.Append("  debugin32:");
            //    temp = sendCmdRet(GET_DEBUG32);
            //    sb.Append(Util.getHex8(temp));
            //}
            //sb.AppendLine();

            if (!isBasic && checkBox4.Checked)
            {
                sb.Append("  pc_record_Index:");
                uint index = sendCmdRet(GET_PC_RECORD_INDEX);
                bool ext = false;
                if ((index & 0x80000000) != 0) {
                    ext = true;
                }
                sb.Append(index);
                sb.AppendLine();
                int cnt = Convert.ToInt32(this.comboBox2.Text);
                index = index & 0xFF;
                for (int i = 0; i < cnt; i++)
                {
                    uint pos = (byte)(index + i - cnt);
                    sb.Append("  pc_record:" + pos + ",");
                    sendCmd(SET_DEBUG_ADDRESS, (0<<8) | pos);
                    uint data0 = sendCmdRet(GET_PC_RECORD_DATA);
                    uint ext0 = sendCmdRet(GET_PC_RECORD_DATA_EXT);
                    sb.Append(Util.getHex8(data0));
                    sb.Append(",");
                    string text = "";
                    switch (ext0)
                    {
                        case 0: text = "0"; break;
                        case 1: text = "1"; break;
                        case 2: text = "2"; break;
                        case 3: text = "3"; break;
                        case 4: text = "4"; break;
                        case 5: text = "5~7"; break;
                        case 6: text = "8~15"; break;
                        case 7: text = "16~31"; break;
                        case 8: text = "32~63"; break;
                        case 9: text = "64~127"; break;
                        case 10: text = "128~255"; break;
                        case 11: text = "256~511"; break;
                        case 12: text = "512~1023"; break;
                        case 13: text = "1024~2047"; break;
                        case 14: text = "2048~4094"; break;
                        case 15: text = "4095"; break;
                    }

                    sb.Append(text);

                    if (ext)
                    {

                        sb.Append(",");

                        sendCmd(SET_DEBUG_ADDRESS, (1 << 8) | pos);
                        uint data1 = sendCmdRet(GET_PC_RECORD_DATA);
                        uint ext1 = sendCmdRet(GET_PC_RECORD_DATA_EXT);
                        
                        sendCmd(SET_DEBUG_ADDRESS, (2 << 8) | pos);
                        uint data2 = sendCmdRet(GET_PC_RECORD_DATA);
                        uint ext2 = sendCmdRet(GET_PC_RECORD_DATA_EXT);

                        sendCmd(SET_DEBUG_ADDRESS, (3 << 8) | pos);
                        uint data3 = sendCmdRet(GET_PC_RECORD_DATA);
                        uint ext3 = sendCmdRet(GET_PC_RECORD_DATA_EXT);

                        sb.Append(Util.getBin4(ext1));
                        sb.Append(",");
                        sb.Append(Util.getHex8(data1));
                        sb.Append(" ");

                        sb.Append(Util.getBin4(ext2));
                        sb.Append(",");
                        sb.Append(Util.getHex8(data2));
                        sb.Append(" ");

                        sb.Append(Util.getBin4(ext3));
                        sb.Append(",");
                        sb.Append(Util.getHex8(data3));
                        sb.Append(" ");
                    }

                    sb.AppendLine();
                }
                sb.AppendLine();
            }

            if (!isBasic && checkBox5.Checked)
            {
                sb.Append("  debug_stash_Index:");
                uint index = sendCmdRet(GET_DEBUG_STASH_INDEX);
                sb.Append(index);
                sb.AppendLine();
                int cnt = (int)(index & 255);// Convert.ToInt32(this.comboBox2.Text);
                for (int i = 0; i < cnt; i++)
                {
                    sb.Append("  debug_stash:" + (byte)(index + i - cnt) + ",");
                    sendCmd(SET_DEBUG_ADDRESS, (uint)(index + i - cnt));
                    temp = sendCmdRet(GET_DEBUG_STASH_DATA);
                    sb.Append(Util.getHex8(temp));
                    sb.AppendLine();
                }
                sb.AppendLine();
            }

            bool halt = this.checkBox1.Checked;

            //sendCmdRet(0x09);
            //uint a = sendCmdRet(0x09);
            //sb.Append("  read cur:" + a);
            //
            //sendCmdRet(0x0A);
            //uint b = sendCmdRet(0x0A);
            //sb.Append("  write cur:" + b);
            //
            //sendCmdRet(0x0D);
            //uint c = sendCmdRet(0x0D);
            //sb.Append("  max len:" + c);
            
            sendCmd(HALT_DEBUG, 1);
            sb.AppendLine();
            int sp = 0;
            sb.Append(" r0:");
            getReg(0x00, sb);
            sb.Append(" r1:");
            getReg(0x01, sb);

            sb.Append("   r2:");
            getReg(0x02, sb);
            sb.Append(" r3:");
            getReg(0x03, sb);
            sb.AppendLine();

            for (int i = 4; i < 8; i++)
            {
                sb.Append(" r" + i + ":");
                getReg((byte)i, sb);
            }
            sb.AppendLine();

            for (int i = 8; i < 16; i++)
            {
                sb.Append(" r" + i + ":");
                getReg((byte)i, sb);
            }
            sb.AppendLine();

            for (int i = 16; i < 24; i++)
            {
                sb.Append(" r" + i + ":");
                getReg((byte)i, sb);
            }
            sb.AppendLine();

            sb.Append(" r24:");
            sp = (int)getReg(24, sb);

            sb.Append("    sp:");
            sp = (int)getReg(30, sb);

            sb.Append("    fp:");
            getReg(28, sb);
            sb.AppendLine();

            sb.Append(" re:");
            getReg(29, sb);

            sb.Append(" ra:");
            getReg(31, sb);
            sb.AppendLine();

            sb.Append("中断向量:");
            for (int i = 32; i < 64; i++)
            {
                sb.Append(" i" + (i - 32) + ":");
                getReg(i, sb);
            }
            sb.AppendLine();

            if (!checkBox1.Checked)
            {
                sendCmd(HALT_DEBUG, 0);
            }

            if (!isBasic && halt && (halt_cpu != 0 || halt_uart != 0))
            {
                temp = getmem((uint)CACHE_CTL + 0x04, null);//sendCmdRet(GET_CACHE_CONFIG);
                sb.Append(" cache:");
                sb.Append(Util.getHex8(temp));

                if (!isBasic)
                {

                    sb.Append(" flush count:");
                    temp = getmem((uint)CACHE_CTL + 0x08, null);//sendCmdRet(GET_FLUSH_COUNT);
                    sb.Append(Util.getHex8(temp));

                    sb.AppendLine();
                }

                if (checkBox6.Checked)
                {
                    sb.AppendLine("stack: ");
                    baseaddr = sp;
                    int start = -Convert.ToInt32(this.comboBox2.Text);
                    int end = Convert.ToInt32(this.comboBox2.Text);
                    for (int i = start * 4; i < end * 4; i += 4)
                    {
                        sb.Append((i == 0 ? "*" : " ") + Util.getHex8((uint)(i + baseaddr)) + ":"); getmem((uint)(baseaddr + i), sb); sb.AppendLine();
                    }

                    baseaddr = 0;
                    sb.AppendLine("code: ");
                    start = -Convert.ToInt32(this.comboBox2.Text);
                    end = Convert.ToInt32(this.comboBox2.Text);
                    for (int i = start * 4; i < end * 4; i += 4)
                    {
                        StringBuilder sb2 = new StringBuilder();
                        uint code = getmem((uint)(pc + i), sb2, false);
                        int target = pc + i;
                        string foundsym = Config.getSym(target, syms);
                        string scode = Config.dasm(syms, cfgs, (uint)code, pc + i, baseaddr);
                        if (i == 0)
                        {
                            sb.AppendLine("----------------------------------------------------------------------------------");
                        }
                        sb.AppendLine((i == 0 ? "*" : " ") + Util.getHex8((uint)(pc + i)) + ":" + scode);
                        if (i == 0)
                        {
                            sb.AppendLine("----------------------------------------------------------------------------------");
                        }
                    }

                    sb.AppendLine("mem: ");
                    baseaddr = Convert.ToInt32(textBox1.Text, 16);
                    start = -Convert.ToInt32(this.comboBox2.Text);
                    end = Convert.ToInt32(this.comboBox2.Text);
                    for (int i = start * 4; i < end * 4; i += 4)
                    {
                        sb.Append("" + Util.getHex8((uint)(baseaddr + i)) + ":"); getmem((uint)(baseaddr + i), sb); sb.AppendLine();
                    }
                }
            }

            this.textBox4.Text = sb.ToString();
        }

        private void textBox4_TextChanged(object sender, EventArgs e)
        {

        }

        //public int getData(int baseCmd, StringBuilder sb)
        //{
        //	byte[] temp;
        //	int val = 0;
        //	portWrite((byte)(baseCmd + 0x3), (byte)0x00); temp = readFromPort(1); val |= temp[0] << 24; if (sb != null) sb.Append(Util.getHex2(temp[0]));
        //	portWrite((byte)(baseCmd + 0x2), (byte)0x00); temp = readFromPort(1); val |= temp[0] << 16; if (sb != null) sb.Append(Util.getHex2(temp[0]));
        //	portWrite((byte)(baseCmd + 0x1), (byte)0x00); temp = readFromPort(1); val |= temp[0] << 8; if (sb != null) sb.Append(Util.getHex2(temp[0]));
        //	portWrite((byte)(baseCmd + 0x0), (byte)0x00); temp = readFromPort(1); val |= temp[0] << 0; if (sb != null) sb.Append(Util.getHex2(temp[0]));
        //	return val;
        //}

        private void button2_Click_1(object sender, EventArgs e)
        {

            uint addr = Convert.ToUInt32(textBox1.Text, 16);

            //NoCache(addr, checkBox8.Checked);

            StringBuilder sb = new StringBuilder();
            if (checkBox9.Checked)
            {
                uint val = getReg((int)addr);
                sb.Append(Util.getHex8(val));
            }
            else
            {
                getmem(addr, sb, checkBox2.Checked);
            }

            textBox2.Text = sb.ToString();
            //getstatus();

            uint inc = Convert.ToUInt32(textBox5.Text, 16);
            addr += inc;
            textBox1.Text = Util.getHex8(addr);
            this.Text = "access time:" + getAccessTime();

        }

        private void button6_Click(object sender, EventArgs e)
        {

            uint addr = Convert.ToUInt32(textBox1.Text, 16);
            uint val = Convert.ToUInt32(textBox2.Text, 16);
            //if (checkBox9.Checked)
            //{
            //    setReg(addr, val);
            //}
            //else
            //{
            setmem(addr, val, false, false);
            //}

            uint inc = Convert.ToUInt32(textBox5.Text, 16);
            addr += inc;
            textBox1.Text = Util.getHex8(addr);

            this.Text = "access time:" + getAccessTime();
        }


        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox1.Checked)
            {
                sendCmd(HALT_DEBUG, 1);
            }
            else
            {
                sendCmd(HALT_DEBUG, 0);
            }

        }

        private void button3_Click_1(object sender, EventArgs e)
        {
            sendCmd(DEBUG_STEP);
            getstatus();
        }

        private void button5_Click(object sender, EventArgs e)
        {
            this.connect(this.afterConnect);
        }


        private void button7_Click(object sender, EventArgs e)
        {
            //for (uint i = 0; i < 16; i++)
            //{
            //    this.sendCmdRet(SET_DEBUG_ADDRESS, i);
            //    uint ret = this.sendCmdRet(0x40, 0);
            //    Console.WriteLine(i + " " + Util.getHex8(ret));
            //}
            //return;
            Form2 form2 = new Form2();
            form2.mainForm = this;
            form2.Show();
            return;

            uint temp = getmem((uint)CACHE_CTL + 0x04, null);//sendCmdRet(GET_CACHE_CONFIG);
            Console.WriteLine(Util.getHex8(temp));
            int cache_config_cache_size = (1 << ((int)(temp & 0xFF))) * 4;//DWORD count
            int cache_config_set_count = 1 << ((int)((temp >> 8) & 0xFF));
            int cache_size = cache_config_cache_size * cache_config_set_count * 2;
            Console.WriteLine(cache_size);

            return;
        }



        List<Config> cfgs;

        private void loadSym()
        {
            cfgs = Config.loadConfig(@"assembler\config.txt");

            syms = new List<CodeSym>();
            FileStream fs = new FileStream("temp.sym", FileMode.Open, FileAccess.Read);
            StreamReader sw = new StreamReader(fs);
            string s = sw.ReadToEnd();
            sw.Close();
            fs.Close();
            foreach (var line in s.Split('\n'))
            {
                if (line != "")
                {
                    CodeSym sym = new CodeSym();
                    sym.pos = int.Parse(line.Split(',')[0]);
                    sym.name = line.Split(',')[1];
                    syms.Add(sym);
                }
            }
        }




        private void button9_Click(object sender, EventArgs e)
        {

            sendCmd(DEBUG_RESET_N, 0);//debug_reset_n<=1'b0

            Thread.Sleep(100);

            sendCmd(DEBUG_RESET_N, 1);

        }

        public void flushDataCache()
        {
            uint temp = getmem((uint)CACHE_CTL + 0x04, null);//sendCmdRet(GET_CACHE_CONFIG);
            Console.WriteLine(Util.getHex8(temp));
            int cache_config_cache_size = (1 << ((int)(temp & 0xFF))) * 4;//DWORD count
            int cache_config_set_count = 1 << ((int)((temp >> 8) & 0xFF));
            int cache_size = cache_config_cache_size * cache_config_set_count * 2;
            Console.WriteLine(cache_size);

            for (int i = 0; i < cache_size; i += cache_config_cache_size)
            {
                this.Text = "cache:" + i.ToString();
                Application.DoEvents();
                getmem((uint)i, null);
            }

            for (int i = 0; i < cache_size; i += cache_config_cache_size)
            {
                this.Text = "cache:" + i.ToString();
                Application.DoEvents();
                getmem((uint)(i + cache_size), null);
            }

        }

        private void button11_Click(object sender, EventArgs e)
        {
            if(this.build.Checked){
                //string batFile = "demo.bat";
                string batFile = "jsdemo.bat";
                Console.Clear();
                Process process = new Process();
                process.StartInfo.FileName = "cmd.exe";
                process.StartInfo.Arguments = "/c \"" + batFile + "\"";
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardError = true;
                process.StartInfo.CreateNoWindow = true;

                // 订阅输出事件
                process.OutputDataReceived += process_OutputDataReceived;

                process.ErrorDataReceived += process_ErrorDataReceived;

                process.Start();

                // 开始异步读取
                process.BeginOutputReadLine();
                process.BeginErrorReadLine();

                // 等待结束
                process.WaitForExit();

                Console.WriteLine("退出码: " + process.ExitCode);
            }
            try
            {
                //{
                //    byte[] data = new byte[128*1024];
                //    Random r = new Random();
                //    r.NextBytes(data);
                //    for (uint baseAddr = 0; baseAddr < 128 * 1024; baseAddr += 1024)//data.Length
                //    {
                //        memBatchWrite1024(data, baseAddr, baseAddr);
                //        this.Text = baseAddr.ToString();
                //        Application.DoEvents();
                //    }
                //}

                loadSym();

                sendCmd(HALT_DEBUG, 1);//halt_uart

                //setmem(0x50000000, 0);//low speed

                loadprog("out.bin");//, baseAddr = 0

                //      end else if (command == 8'h02) begin debug_reset_n<=data[0]; command_done<=1;

                //debug mode
                sendCmd(SET_DEBUG_FLG, 1);
                //sendCmd(SET_DEBUG_FLG, 0);

                sendCmd(DEBUG_RESET_N, 0);
                sendCmd(DEBUG_RESET_N, 1);

                //if (checkBox11.Checked)
                //{
                //    setmem(0x50000000, 1);//high speed
                //}
                //else
                //{
                //    setmem(0x50000000, 0);//low speed
                //}

                if (!checkBox1.Checked)
                {
                    sendCmd(HALT_DEBUG, 0);//halt_uart<=1'b0
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }
        }

        void process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (!string.IsNullOrEmpty(e.Data))
            {
                Console.WriteLine("[错误] " + e.Data);
            }
        }

        void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (!string.IsNullOrEmpty(e.Data))
            {
                Console.WriteLine(e.Data);
            }
        }
        public void loadprog(string filename)
        {
            Random r = new Random();
            FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
            int len = (int)fs.Length;
            int orilen = len;
            int diff = len & (packageSize - 1);
            len += packageSize - diff;
            byte[] data = new byte[len];
            fs.Read(data, 0, (int)fs.Length);
            fs.Close();
            uint baseAddr;
            //for (baseAddr = 0; baseAddr < len; baseAddr += 1024)//data.Length
            //{
            //    memBatchWrite1024(data, baseAddr, baseAddr);
            //    //FlushCache(baseAddr, 1024);
            //    //Console.WriteLine(baseAddr);
            //    this.Text = baseAddr.ToString();
            //    Application.DoEvents();
            //}
            writeMem(0, data);

            flushDataCache();
            byte[] readout = new byte[len];
            int err = 0;
            //for (baseAddr = 0; baseAddr < len; baseAddr += 1024)//data.Length
            //{
            //    memBatchRead1024(buff, baseAddr);
            //    for (uint i = 0; i < 1024; i += 4)
            //    {
            //        bool fix = false;
            //        if (buff[i + 0] != data[i + 0 + baseAddr]) { err++; fix = true; }
            //        if (buff[i + 1] != data[i + 1 + baseAddr]) { err++; fix = true; }
            //        if (buff[i + 2] != data[i + 2 + baseAddr]) { err++; fix = true; }
            //        if (buff[i + 3] != data[i + 3 + baseAddr]) { err++; fix = true; }
            //        if (fix)
            //        {
            //            uint val = 0;
            //            val |= (uint)data[i + 0 + baseAddr] << 0;
            //            val |= (uint)data[i + 1 + baseAddr] << 8;
            //            val |= (uint)data[i + 2 + baseAddr] << 16;
            //            val |= (uint)data[i + 3 + baseAddr] << 24;
            //            setmem(i + baseAddr, val);
            //            FlushCache(i + baseAddr, 1);
            //            Console.WriteLine("fix" + Util.getHex8(i + baseAddr) + ":" + Util.getHex2(buff[i + 3]) + Util.getHex2(buff[i + 2]) + Util.getHex2(buff[i + 1]) + Util.getHex2(buff[i + 0]) + "=>" + Util.getHex8(val));
            //            baseAddr -= 1024; break;
            //        }
            //    }
            //    if (err > 100) break;
            //    this.Text = baseAddr.ToString();
            //    Application.DoEvents();
            //}
            readMem(0, readout);
            int errCnt = 0;
            for (int i = 0; i < len; i += 4)
            {
                if (data[i] != readout[i])
                {
                    err++;
                }
                uint v1 = 0;
                {
                    v1 |= (((uint)data[i + 0]) & 0xFF);
                    v1 |= (((uint)data[i + 1]) & 0xFF) << 8;
                    v1 |= (((uint)data[i + 2]) & 0xFF) << 16;
                    v1 |= (((uint)data[i + 3]) & 0xFF) << 24;
                }
                uint v2 = 0;
                {
                    v2 |= (((uint)readout[i + 0]) & 0xFF);
                    v2 |= (((uint)readout[i + 1]) & 0xFF) << 8;
                    v2 |= (((uint)readout[i + 2]) & 0xFF) << 16;
                    v2 |= (((uint)readout[i + 3]) & 0xFF) << 24;
                }

                if (v1 != v2)
                {
                    err++;
                    errCnt++;
                    if (errCnt > 64)
                    {
                        break;
                    }
                    Console.WriteLine(i + "," + Util.getHex8(v1) + "," + Util.getHex8(v2) + ", " + (v1 != v2 ? "x" : " "));
                }
            }


            {
                setmem((uint)CACHE_CTL + 0x04, 1);
                setmem((uint)CACHE_CTL + 0x04, 0);
            }

            //reset reg
            //for (int i = 0; i < 2048; i++)
            //{
            //    buff[i] = 0;
            //}
            //send(buff);

            textBox4.Text = "err:" + err.ToString();
        }

        public bool videoing = false;
        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            if (videoing)
            {
                this.textBox7.Text = "" + ((uint)(-trackBar1.Value * 2));
            }
            else
            {
                sendCmd(SET_DEBUG_VGA_BASE_ADDR, 0x80000000 | (uint)(-trackBar1.Value));
                this.Text = "" + ((uint)(-trackBar1.Value));
            }
        }
        void trackBar1_MouseUp(object sender, MouseEventArgs e)
        {
            if (videoing)
            {
                this.textBox7.Text = "" + ((uint)(-trackBar1.Value * 2));
            }
            else
            {
                sendCmd(SET_DEBUG_VGA_BASE_ADDR, 0);
            }
        }

        void trackBar1_MouseDown(object sender, MouseEventArgs e)
        {
            if (videoing)
            {

            }
            else
            {
                sendCmd(SET_DEBUG_VGA_BASE_ADDR, 0x80000000 | (uint)(-trackBar1.Value * 2));
            }
        }


        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {
        }

        private void checkBox3_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox3.Checked)
            {
                //setmem(0x4C000000, 0x00010000);
                sendCmdNoRes(SET_VGA_CONTROL, 1);
            }
            else
            {
                //setmem(0x4C000000, 0);
                sendCmdNoRes(SET_VGA_CONTROL, 0);
            }

        }

        private void button16_Click_1(object sender, EventArgs e)
        {
            Form3 form3 = new Form3();
            form3.mainForm = this;
            form3.Show();
        }

        private void checkBox8_CheckedChanged(object sender, EventArgs e)
        {
            if (checkBox8.Checked)
            {
                sendCmd(DEBUG_NOCACHE, 1);
            }
            else
            {
                sendCmd(DEBUG_NOCACHE, 0);
            }
        }

        public void writeReg(uint addr, uint val)
        {
            sendCmd(SET_DEBUG_ADDRESS, addr);
            sendCmdRet(0x1E, val);
        }


        //uint[] regArray = new uint[32];
        private uint readReg(int addr)
        {
            //uint val = regArray[index];
            sendCmd(SET_DEBUG_ADDRESS, (uint)addr);
            uint val = sendCmdRet(0x1D);
            return val;
        }

        //uint[] regArray = new uint[32];
        private uint getReg(int addr, StringBuilder sb = null)
        {
            //uint val = regArray[index];
            sendCmd(SET_DEBUG_ADDRESS, (uint)(addr*2));
            uint val = sendCmdRet(0x1D);
            if (sb != null)
            {
                sb.Append(Util.getHex8(val));
            }
            return val;
        }

        public uint getmem(uint addr, StringBuilder sb = null, bool isIns = false)
        {
            if (waitRequest != 0) {
                return 0x12345678;
            }
            if (BaseType == "cy7c68031a")
            {
                //sendCmd(SET_DEBUG_RW_CMD, 0);//ldw
            }
            sendCmd(SET_DEBUG_ADDRESS, addr);
            uint val;
            if (isIns)
            {
                val = sendCmdRet(INS_READ);
            }
            else
            {
                val = sendCmdRet(MEM_READ);
            }
            if (sb != null)
            {
                sb.Append(Util.getHex8(val));
            }
            return val;
        }

        public bool setmem(uint addr, uint data, bool noerr = false, bool no31 = false)
        {
            //if (BaseType == "cy7c68031a")
            //{
            //    int byteEnable = comboBox1.SelectedIndex;
            //    uint debug_rw_cmd = 1;
            //    switch (byteEnable)
            //    { //0: DW  1:word 2: byte
            //        case 0: debug_rw_cmd = 1; break;//3'b001;//stw
            //        case 1: debug_rw_cmd = 7; break;//3'b111;//sth
            //        case 2: debug_rw_cmd = 6; break;//3'b110;//stb
            //    }
            //    sendCmd(SET_DEBUG_RW_CMD, debug_rw_cmd);
            //}
            sendCmd(SET_DEBUG_ADDRESS, addr);
            sendCmd(SET_DEBUG_WRITEDATA, data);

            if (!no31)
            {
                sendCmd(MEM_WRITE);
            }
            return true;
        }


        private void button8_Click_1(object sender, EventArgs e)
        {

            Form4 form = new Form4();
            form.mainForm = this;
            form.Show();
        }

        private void checkBox11_CheckedChanged(object sender, EventArgs e)
        {
            //video
            checkBox1.Checked = true;
            if (checkBox11.Checked)
            {
                //setmem(0x50000000, 1);
                sendCmd(SET_CPU_CLK, 1);
            }
            else
            {
                //setmem(0x50000000, 0);
                sendCmd(SET_CPU_CLK, 0);
            }
        }

        private void textBox7_TextChanged(object sender, EventArgs e)
        {

        }

        void dummy()
        {

            sendCmdNoRes(0x03);
            sendCmdNoRes(0x02);
        }

        public void readMem(uint addr, byte[] buff)
        {
            int retry = 0;
            uint length = (uint)buff.Length;
            while (true)
            {
                try
                {
                    sendCmd(SET_DEBUG_ADDRESS, addr);
                    sendCmd(SET_DEBUG_LENGTH, length);
                    sendCmdNoRes(MEM_READ_TRANS);

                }
                catch (Exception ex)
                {
                    Console.WriteLine("reconnect");
                    this.connect(this.dummy);
                    continue;
                }

                bool result = receive(buff, length);
                if (result)
                {
                    break;

                }
                else
                {
                    try
                    {
                        sendCmdNoRes(0x03);
                        sendCmdNoRes(0x02);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("reconnect");
                        this.connect(this.dummy);
                        continue;
                    }

                    return;
                    Console.WriteLine("retry");
                    if (retry++ > 2)
                    {
                        Console.WriteLine("reconnect");
                        this.connect(this.dummy);
                    }
                }
            }
        }
        public void writeMem(uint addr, byte[] buff)
        {
            int retry = 0;
            while (true)
            {
                try
                {
                    sendCmd(SET_DEBUG_ADDRESS, addr);
                    sendCmd(SET_DEBUG_LENGTH, (uint)buff.Length);
                    sendCmdNoRes(MEM_WRITE_TRANS);

                }
                catch (Exception ex)
                {
                    Console.WriteLine("reconnect");
                    this.connect(this.dummy);
                    continue;
                }

                bool result = send(buff, (uint)buff.Length);
                if (result)
                {
                    break;

                }
                else
                {
                    try
                    {
                        sendCmdNoRes(0x03);
                        sendCmdNoRes(0x02);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("reconnect");
                        this.connect(this.dummy);
                        continue;
                    }

                    return;
                    Console.WriteLine("retry");
                    if (retry++ > 2)
                    {
                        Console.WriteLine("reconnect");
                        this.connect(this.dummy);
                    }
                }
            }
        }

        bool stop = true;
        void test()
        {
            Random r = new Random();

            uint packageSize = uint.Parse(textBox3.Text) * 1024 * 1024;
            uint packageCount = uint.Parse(textBox8.Text);

            byte[][] write = new byte[packageCount][];
            for (int i = 0; i < packageCount; i++)
            {
                write[i] = new byte[packageSize];
            }

            byte[] read = new byte[packageSize];


            int cnt = 0;
            while (!stop && cnt<int.Parse(textBox10.Text))
            {
                int totalerr = 0;
                try
                {
                    for (int i = 0; i < packageCount; i++)
                    {
                        r.NextBytes(write[i]);
                    }

                    for (uint i = 0; i < packageCount; i++)
                    {
                        Stopwatch sw = new Stopwatch();
                        sw.Start();
                        writeMem(i * packageSize, write[i]);
                        sw.Stop();
                        long time = sw.ElapsedMilliseconds;
                        double speedw = Math.Round((packageSize / 1024.0 / 1024.0) * 100000.0 / time) / 100;
                        Console.WriteLine("package:" + i + ", speedw:" + speedw);
                    }

                    for (uint j = 0; j < packageCount; j++)
                    {
                        Stopwatch sw = new Stopwatch();
                        sw.Start();
                        readMem(j * packageSize, read);
                        sw.Stop();
                        long time = sw.ElapsedMilliseconds;
                        double speedr = Math.Round((packageSize / 1024.0 / 1024.0) * 100000.0 / time) / 100;

                        totalerr += compair((int)packageSize, write[j], read, 60, 32);


                        Console.WriteLine("package:" + j + ", speedr:" + speedr);
                    }

                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                    break;
                }

                Console.WriteLine("totalerr:" + totalerr);
                cnt++;
            }
        }

        private void button13_Click(object sender, EventArgs e)
        {
            //dump mem
            uint packageSize = uint.Parse(textBox3.Text) * 1024 * 1024;
            uint packageCount = uint.Parse(textBox8.Text);

            byte[][] read = new byte[packageCount][];
            for (int i = 0; i < packageCount; i++)
            {
                read[i] = new byte[packageSize];
            }

            readMem(packageSize, read[0]);
            FileStream fs = new FileStream("mem.dmp", FileMode.Create, FileAccess.Write);
            for (uint j = 0; j < packageCount; j++)
            {
                readMem(j * packageSize, read[j]);
                fs.Write(read[j], 0, (int)packageSize);
            }
            fs.Close();


        }
        private void button12_Click_1(object sender, EventArgs e)
        {
            stop = !stop;
            if (!stop)
            {
                Thread t = new Thread(test);
                t.Start();
                //test();
            }

        }

        [StructLayoutAttribute(LayoutKind.Explicit)]
        struct UFI
        {
            [FieldOffsetAttribute(0)]
            public float fv;
            [FieldOffsetAttribute(0)]
            public uint iv;
        }

        private void button1_Click_1(object sender, EventArgs e)
        {
            float f = float.Parse(textBox9.Text);
            UFI ufi;
            ufi.iv = 0;
            ufi.fv = f;
            textBox9.Text = Util.getHex8(ufi.iv);
        }

        private void button10_Click(object sender, EventArgs e)
        {
            uint f = Convert.ToUInt32(textBox9.Text, 16);
            UFI ufi;
            ufi.fv = 0.0f;
            ufi.iv = f;
            textBox9.Text = "" + ufi.fv;

        }

        static int find(uint v2, int size, byte[] buff)
        {
            for (int i = 0; i < size; i += 4)
            {
                uint v1 = 0;
                if (buff != null)
                {
                    v1 |= (((uint)buff[i + 0]) & 0xFF);
                    v1 |= (((uint)buff[i + 1]) & 0xFF) << 8;
                    v1 |= (((uint)buff[i + 2]) & 0xFF) << 16;
                    v1 |= (((uint)buff[i + 3]) & 0xFF) << 24;
                }
                if (v2 == v1)
                {
                    return i;
                }
            }
            return -1;
        }

        public static int compair(int size, byte[] buffa, byte[] buffb, int correctCount, int errMax)
        {
            int err = 0;
            for (int i = 0; i < size; i += 4)
            {
                uint v1 = 0;
                if (buffa != null)
                {
                    v1 |= (((uint)buffa[i + 0]) & 0xFF);
                    v1 |= (((uint)buffa[i + 1]) & 0xFF) << 8;
                    v1 |= (((uint)buffa[i + 2]) & 0xFF) << 16;
                    v1 |= (((uint)buffa[i + 3]) & 0xFF) << 24;
                }
                uint v2 = 0;
                {
                    v2 |= (((uint)buffb[i + 0]) & 0xFF);
                    v2 |= (((uint)buffb[i + 1]) & 0xFF) << 8;
                    v2 |= (((uint)buffb[i + 2]) & 0xFF) << 16;
                    v2 |= (((uint)buffb[i + 3]) & 0xFF) << 24;
                }

                if (v1 != v2)
                {
                    err++;
                    if (err < errMax)
                    {
                        int addr = find(v2, size, buffa);
                        uint diff = v1 ^ v2;
                        Console.WriteLine(i + ",true:" + Util.getHex8(v1) + "," + Util.getHex8(v2) + ", " + (v1 != v2 ? "x" : " ") + " diff:" + Util.getHex8(diff) + " addr:" + Util.getHex8(addr));
                    }
                }
                else if (i < correctCount)
                {
                    Console.WriteLine(i + ",true:" + Util.getHex8(v1) + "," + Util.getHex8(v2) + ", " + (v1 != v2 ? "x" : " "));
                }
            }
            Console.WriteLine("err:" + err);
            return err;
        }



    }
}
